<template>
  <div class="flex flex-row w-full book-marker">
    <div class="flex-1">
      <div class="ai-label_drawer">
        <div :id="mapId"></div>
        <div class="tools">
          <el-tooltip :content="item.label" placement="right" effect="light" v-for="item in markTypes" :key="item.value">
            <el-button size="small" @click="setMode(item.mode, item.value, item.label)">
              {{ item.label }}
            </el-button>
          </el-tooltip>
        </div>

      </div>
    </div>
    <el-aside class="right-side">
      <MarkerListVue @onSelectFeature="selectFeature" @onHandleDelete="handleDelete"
        @onMarkTypeChanged="onMarkTypeChanged" v-if="!showPlusMarkerDialog"></MarkerListVue>
      <MarkerPlusVue v-if="showPlusMarkerDialog" @on-close="showPlusMarkerDialog = false"></MarkerPlusVue>
    </el-aside>
  </div>
</template>
  
<script lang="ts" setup>
import MarkerListVue from "./MarkerList.vue";
import MarkerPlusVue from "./MarkerPlus.vue";
import { ref, reactive, watch } from "vue";
import AILabel from "ailabel";
import { useBookEditorStore, type Marker } from "@/stores/modules/wisdbookMarker";
import { storeToRefs } from "pinia";
import { ElMessage } from "element-plus";
import {
  delMark,
  addMark,
  getPage,
  updateMark,
} from "@/api/wisdbook/marker";

let leftTabIndex = ref(0);  //左侧选中的tab

//动态画板ID，解决chrome生产环境画板无法清空的问题，这个问题只有chrome存在，目前不清楚原因
let mapId = ref("ai-map" + Math.floor(Math.random() * 100))
let { bookId, pages, currectPage, currectPlusMarker, currectPageId, markTypes } = storeToRefs(useBookEditorStore());
let gMap: any = null;
let gFirstFeatureLayer: any = reactive({});
let gFirstTextLayer: any = reactive({}); // text 文本图层，用于展示文本
let imgUrl: any = ref(""); //当前图片URL
let markerList: any = reactive([]); //当前图片的标记
let imageWidth = 1080; //当前图片尺寸
let imageHeight = 1516; //当前图片尺寸
let drawingStyle = {
  //绘制样式
  strokeStyle: "#0f0",
  lineWidth: 1,
  fillStyle: "#0f0",
  globalAlpha: 0.1,
  fill: true,
  stroke: true,
};

let drawingStyleChild = {
  //孩子绘制样式
  strokeStyle: "#306EFF",
  lineWidth: 1,
  fillStyle: "#306EFF",
  globalAlpha: 0.1,
  fill: true,
  stroke: true,
};


// 文本显示 style
let drawingTextStyle = {
  fillStyle: "#0f0",
  strokeStyle: "#0f0",
  background: true,
  globalAlpha: 0.9,
  fontColor: "#00f",
};
// 文本样式，有挂接资源的样式
let drawingTextStyleHasResource = {
  fillStyle: "#E59866",
  strokeStyle: "#E59866",
  background: true,
  globalAlpha: 0.9,
  fontColor: "#A04000",
};

let defaultMarkType = markTypes.value[0]; // 默认的标记名称
let lastSelectMarker: any = ""; // 上一次选中的标记
let showPlusMarkerDialog = ref(false); //是否显示追加框
let currectEditContextMarkerId = ref(""); //当前正在资源挂接的marker ID
let contextEditdialogVisible = ref(false); //显示资源挂接对话框


//加载指定的页面
const iniPage = () => {
  imgUrl.value = currectPage.value.pageImg;
  getPage({ pageId: currectPage.value.id }).then((data: any) => {
    currectPage.value.markerList = data;
    // shape需要做一下类型转换，原因是axios过滤器把大数转成字符串了，不利于后续操作
    currectPage.value.markerList.forEach(item => {
       item.shape={
        x:Number(item.shape.x),
        y:Number(item.shape.y),
        width:Number(item.shape.width),
        height:Number(item.shape.height),
       }
    });
    markerList = currectPage.value.markerList;
    let img = new Image();
    img.src = imgUrl.value;
    img.onload = function () {
      imageWidth = img.width;
      imageHeight = img.height;
      initMap();
    };
  });
};

iniPage();
//监听currectPageId变化时，重载数据
watch(currectPageId, () => {
  iniPage();
})

//初始化画板
const initMap = () => {
  lastSelectMarker = "";
  if (gMap == null) {
    gMap = new AILabel.Map(mapId.value, {
      center: { x: imageWidth / 2, y: imageHeight / 2 }, // 为了让图片居中
      zoom: imageWidth * 2.5,
      mode: "PAN", // PAN 可以平移和放大缩小   ban  可以平移
      refreshDelayWhenZooming: false, // 缩放时是否允许刷新延时，性能更优
      zoomWhenDrawing: true,
      panWhenDrawing: false, //绘制时可到边界外自动平移
      zoomWheelRatio: 5, // 控制滑轮缩放缩率[0, 10), 值越小，则缩放越快，反之越慢
      withHotKeys: true, // 快捷键开关
      featureCaptureWhenMove: false, //绘制过程中是否开启‘双击选中’tip提示，耗费性能（会持续进行move捕捉判断）
    });

    // 绘制结束时触发
    gMap.events.on("drawDone", AILabelDrawDone);
    // 在绘制模式下双击 feature 触发选中
    gMap.events.on("featureSelected", AILabelFeatureSelected);
    // 当模式切换或单击其他地方触发
    gMap.events.on("featureUnselected", AILabelFeatureUnselected);
    //feature 编辑完成触发
    gMap.events.on("featureUpdated", AILabelFeatureUpdated);
  }


  gMap.setActiveFeature(null); //取消选中
  gMap.removeAllLayers(); //清除所有图层，重新添加
  gMap.markerLayer.removeAllMarkers(); // 清除所有标记，重新标记
  // 图片层添加
  const gFirstImageLayer = new AILabel.Layer.Image(
    "layer-image", // id
    {
      src: imgUrl.value,
      width: imageWidth,
      height: imageHeight,
      crossOrigin: false, // 如果跨域图片，需要设置为true
      position: {
        // 左上角相对中心点偏移量
        x: 0,
        y: 0,
      }
    }, // imageInfo
    { name: "图片图层" }, // props
    { zIndex: 1 } // 这里写样式 层级
  );
  // 添加到gMap对象
  gMap.addLayer(gFirstImageLayer);

  gFirstFeatureLayer = new AILabel.Layer.Feature(
    "first-layer-feature", // id
    { name: "矢量图层" }, // props
    { zIndex: 2 } // style
  );
  gMap.addLayer(gFirstFeatureLayer);
  gFirstTextLayer = new AILabel.Layer.Text(
    "first-layer-text", // id
    { name: "文本图层" }, // props
    { zIndex: 3, opacity: 1 } // style
  );
  gMap.addLayer(gFirstTextLayer);
  window.onresize = function () {
    gMap && gMap.resize();
  };
  iniMarkList();
};

//绘制本页所有已标记的内容到画板
const iniMarkList = () => {
  for (const element of markerList) {
    const marker = element
    if (marker.featureType == "RECT") {
      const rectFeatureId = marker.id;
      const relatedTextId = `rect-label-text-id-${guid()}`;
      const relatedDeleteMarkerId = `rect-delete-marker-id-${guid()}`;
      const relatedPlusMarkerId = `rect-plus-marker-id-${guid()}`;
      let _drawingStyle = drawingStyle;

      //把父亲和孩子标注样式弄成一致
      if (marker.childs && (marker.childs.length > 0 || marker.pid != "")) {
        _drawingStyle = drawingStyleChild;
      }

      console.log("rectFeatureId:", rectFeatureId);
      //文字标签，使用新的ID
      marker.props = {
        textId: relatedTextId,
        deleteMarkerId: relatedDeleteMarkerId, // 删除图标的id
        plusMarkerId: relatedPlusMarkerId, //追加图标id
      };

      // 绘制矩形 feature
      const rectFeature = new AILabel.Feature.Rect(
        rectFeatureId, // id
        marker.shape, // shape，空间信息
        {
          textId: relatedTextId,
          deleteMarkerId: relatedDeleteMarkerId, // 删除图标的id
          plusMarkerId: relatedPlusMarkerId, //追加图标id
        },
        _drawingStyle // style，样式
      );
      gFirstFeatureLayer.addFeature(rectFeature);

      addLayerTextToMarker(marker);
    }
  }
};



// AILabel 绘制结束时触发
const AILabelDrawDone = (type: any, data: any) => {
  console.log("--AILabelDrawDone data--", type, data);
  // 绘制矩形
  if (type === "RECT") {
    // 文本ID，删除图标的 id，矩形 ID
    const rectFeatureId = `rect-feature-id-${guid()}`;
    const relatedTextId = `rect-label-text-id-${guid()}`;
    const relatedDeleteMarkerId = `rect-delete-marker-id-${guid()}`;
    const relatedPlusMarkerId = `rect-plus-marker-id-${guid()}`;
    // 创建新的标记
    const mark: Marker = {
      featureType: "RECT",
      id: rectFeatureId,
      pid: "",
      ppageId: 0,
      pageId: currectPage.value.id,
      markType: defaultMarkType.value,
      shape: data,
      props: {
        textId: relatedTextId,
        deleteMarkerId: relatedDeleteMarkerId, // 删除图标的id
        plusMarkerId: relatedPlusMarkerId, //追加图标id
      },
      childs: [],
      resourceTotal:0
    };

    if (showPlusMarkerDialog.value) {
      // 如果当前正在给某个标记追加标记，则把本标注添加到其孩子中
      mark.pid = currectPlusMarker.value.id;
      mark.ppageId = currectPlusMarker.value.pageId;
      currectPlusMarker.value.childs.push(mark);
    }

    let _drawingStyle = drawingStyle;

    if (mark.childs.length > 0 || mark.pid != "") {
      //如果该标注有父亲，则用改变样式
      _drawingStyle = drawingStyleChild;
    }
    // 绘制矩形 feature
    const rectFeature = new AILabel.Feature.Rect(
      rectFeatureId, // id
      data, // shape，空间信息
      {
        textId: relatedTextId,
        deleteMarkerId: relatedDeleteMarkerId, // 删除图标的id
        plusMarkerId: relatedPlusMarkerId, //追加图标id
      },
      _drawingStyle // style，样式
    );
    gFirstFeatureLayer.addFeature(rectFeature);

    addLayerTextToMarker(mark);
    markerList.push(mark);
    addMark(mark).then((data: any) => {
      console.log("保存mark:", data)
    });

  }
  
};
// 当模式切换或单击其他地方触发
const AILabelFeatureUnselected = (feature: any) => {
  console.log("--AILabelFeatureUnselected--", feature);
  markerList.forEach((element: any) => {
    element.selected = false;
  });
  // 取消高亮，移除 删除marker
  gMap.setActiveFeature(null);
  gMap.markerLayer.removeMarkerById(feature.props.deleteMarkerId);
  // 删除对应的追加marker
  gMap.markerLayer.removeMarkerById(feature.props.plusMarkerId);
  gMap.markerLayer.removeMarkerById(feature.props.contextMarkerId);
};
// 在绘制模式下双击 feature 触发选中
const AILabelFeatureSelected = (feature: any) => {
  console.log("--AILabelFeatureSelected--", feature);
  const itemIndex = markerList.findIndex((ele: any) => ele.id === feature.id);
  selectFeature(itemIndex);
};

const AILabelFeatureUpdated = (feature: any, shape: any) => {
  console.log("--FeatureUpdated--", feature, shape);
  feature.updateShape(shape);
  // 标注列表对应项也更新 shape
  const itemIndex = markerList.findIndex((ele: any) => ele.id === feature.id);
  const item = markerList.find((ele: any) => ele.id === feature.id);
  item.shape = shape;
  markerList.splice(itemIndex, 1, item);

  updateMark(item).then((data: any) => {
    console.log("更新mark:", data);
    const deleteMarkerId = feature.props.deleteMarkerId;
    const plusMarkerId = feature.props.plusMarkerId;
    // const contextMarkerId = feature.props.contextMarkerId;
    const textId = feature.props.textId;


    if (feature.type === "RECT") {
      console.log("---更新矩形---");
      // 更新marker位置
      const targetMarker = gMap.markerLayer.getMarkerById(deleteMarkerId);
      console.log("--targetMarker--", targetMarker);
      targetMarker.updatePosition(feature.getPoints()[1]);

      // 更新marker位置
      const plusMarker = gMap.markerLayer.getMarkerById(plusMarkerId);
      console.log("--targetMarker--", plusMarker);
      plusMarker.updatePosition(feature.getPoints()[1]);

      // 更新marker位置
      // const contextMarker = gMap.markerLayer.getMarkerById(contextMarkerId);
      // console.log("--targetMarker--", contextMarker);
      // contextMarker.updatePosition(feature.getPoints()[1]);

      // 更新text位置
      const targetText = gFirstTextLayer.getTextById(textId);
      console.log("--targetText--", targetText);
      targetText.updatePosition(feature.getPoints()[0]);
    }
  });
};


const onMarkTypeChanged = (marker: Marker) => {
  console.log("onMarkTypeChanged:",marker);
  let textId = marker.props.textId;
  const targetText = gFirstTextLayer.getTextById(textId);
  console.log("--targetText--", targetText);
  updateMark(marker).then((data: any) => {
    const label: any = getMarkerLabel(marker);
    targetText.textInfo.text=label
    targetText.refresh();
  });
};



// 删除按钮
const handleDelete = (row: any) => {
  // 标注列表对应项也删除
  const itemIndex = markerList.findIndex((ele: any) => ele.id === row.id);
  delMark(row).then((data: any) => {
    console.log("删除mark:", data);
    // 首先删除当前 marker
    if (row.props?.deleteMarkerId) {
      gMap.markerLayer.removeMarkerById(row.props.deleteMarkerId);
      gMap.markerLayer.removeMarkerById(row.props.plusMarkerId);
      // gMap.markerLayer.removeMarkerById(row.props.contextMarkerId);
      // 删除对应 text
      gFirstTextLayer.removeTextById(row.props.textId);
    }
    // 删除对应 feature
    gFirstFeatureLayer.removeFeatureById(row.id);
    markerList.splice(itemIndex, 1);
    //删除所有孩子:
    if (row.childs && row.childs.length > 0) {
      row.childs.forEach((element: any) => {
        handleDelete(element);
      });
    }
  });

  //删除正在追加的标注:
  if (currectPlusMarker.value?.id == row.id) {
    currectPlusMarker.value = {};
    showPlusMarkerDialog.value = false;
  }

  //如果自己是孩子，则遍历所有页面，在所有标注的孩子里删除自己
  if (row.pid != "") {
    const page = pages.value.find((ele) => ele.id === row.ppageId); //找到父亲所在的页面
    if (page) {
      console.log("page", page);
      const parentMark = page.markerList.find((ele) => ele.id === row.pid); //找到父亲
      if (parentMark && parentMark.childs) {
        //从父亲的孩子里删除自己
        // console.log("parentMark", parentMark);
        const itemIndex = parentMark.childs.findIndex(
          (ele) => ele.id === row.id
        );
        // console.log("itemIndex", itemIndex);
        parentMark.childs?.splice(itemIndex, 1);
      }
    }
  }
};





import iconDel from '@/assets/icons/icon_label_del.png'
import iconPlus from '@/assets/icons/icon_label_plus.png'
// 添加删除marker
const addDeleteMarker = (feature: any, markerPosition: any) => {
  console.log("addDeleteMarker:feature:", feature, "  ", markerPosition)
  const markerId = feature.props.deleteMarkerId;
  // 添加 delete-icon
  const gFirstMarker = new AILabel.Marker(
    markerId, // id
    {
      src: iconDel,
      position: markerPosition, // marker 位置
      offset: {
        x: -20,
        y: -4,
      },
    }, // markerInfo
    { name: "内容编辑marker" } // props
  );

  gFirstMarker.events.on("click", () => {
    // 标注列表对应项也删除
    const item = markerList.find((ele: any) => ele.id === feature.id);
    handleDelete(item);
  });
  gMap.markerLayer.addMarker(gFirstMarker);
};

// 添加追加marker
const addPlusMarker = (feature: any, markerPosition: any) => {
  const markerId = feature.props.plusMarkerId;
  const gFirstMarker = new AILabel.Marker(
    markerId,
    {
      src: iconPlus,
      position: markerPosition, // marker 位置
      offset: {
        x: -40,
        y: -4,
      },
    }, // markerInfo
    { name: "追加 marker" } // props
  );
  gMap.markerLayer.addMarker(gFirstMarker);

  gFirstMarker.events.on("click", () => {
    // 标注列表对应项也删除
    const item = markerList.find((ele: any) => ele.id === feature.id);
    currectPlusMarker.value = item;
    showPlusMarkerDialog.value = true;
    console.log("选在追加标记：", currectPlusMarker);
  });
};

const selectFeature = (index: number) => {
  markerList.forEach((element: any) => {
    element.selected = false;
  });
  let marker = markerList[index];
  marker.selected = true;
  // 如果当前行的 id 不等于 上次点击行的 id ，则取消上次的高亮和marker
  if (lastSelectMarker !== "" && marker.id !== lastSelectMarker.id) {
    // 取消高亮，移除 删除marker
    gMap.setActiveFeature(null);
    gMap.markerLayer.removeMarkerById(lastSelectMarker.props.deleteMarkerId);
    gMap.markerLayer.removeMarkerById(lastSelectMarker.props.plusMarkerId);
    gMap.markerLayer.removeMarkerById(lastSelectMarker.props.contextMarkerId);
  }
  gMap.markerLayer.removeMarkerById(marker.props.deleteMarkerId);
  gMap.markerLayer.removeMarkerById(marker.props.plusMarkerId);
  gMap.markerLayer.removeMarkerById(marker.props.contextMarkerId);
  // 取消上次的高亮之后，再次高亮当前的 feature
  // 高亮选中 feature
  const feature = gFirstFeatureLayer.getFeatureById(marker.id);
  gMap.setActiveFeature(feature);
  if (marker.featureType === "RECT") {
    console.log('--添加删除图标--')
    const markerPosition = feature.getPoints()[1];
    addDeleteMarker(feature, markerPosition);


    if (marker.pid == "") {
      console.log('--添加内容和追加图标--')
      // 如果自己是别人的孩子，则不能添加孩子
      addPlusMarker(feature, markerPosition);
    }
  } else if (marker.featureType === "POLYGON") {
    // 绘制多边形
    // console.log('--多边形 添加删除图标 marker--')
    const markerPosition = feature.shape.points[1];
    addDeleteMarker(feature, markerPosition);
    addPlusMarker(feature, markerPosition);
  }
  lastSelectMarker = marker;
};

// 添加文本
const addLayerText = (textId: any, textName: any, textPosition: any) => {
  // 添加一个文本
  const gFirstText = new AILabel.Text(
    textId, // id
    { text: textName, position: textPosition, offset: { x: 0, y: 0 } },
    { name: textName }, // props
    drawingTextStyle
  );
  gFirstTextLayer.addText(gFirstText);
};


/**
 * 给标记添加显示文字
 * @param marker 
 */
const addLayerTextToMarker = (marker:Marker) => {
  
  const { x: ltx, y: lty } = marker.shape;
  let label = getMarkerLabel(marker);
  let _drawingTextStyle=drawingTextStyle;

  //如果标签下资源挂接数量大于0，则改变颜色，显示数量
  if(marker.resourceTotal>0){
    _drawingTextStyle=drawingTextStyleHasResource;
    label+=` [${marker.resourceTotal}]`
  }

  const gFirstText = new AILabel.Text(
    marker.props?.textId, // id
    { text: label, position: { x: ltx, y: lty }, offset: { x: 0, y: 0 } },
    { name: label }, // props
    _drawingTextStyle
  );
  gFirstTextLayer.addText(gFirstText);
};

const setMode = (mode: any, labelId: string, textName: string) => {
  console.log("mode:", mode);
  defaultMarkType = { mode: mode, value: labelId, label: textName };
  gMap.setMode(mode);
  //  动态颜色可以在这里赋值 精确到某一个操作
  // 后续对应模式处理
  switch (mode) {
    case "PAN": {
      break;
    }
    case "RECT": {
      gMap.setDrawingStyle(drawingStyle);
      break;
    }
    default:
      break;
  }
};

const guid = (): string => {
  return `xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx`
    .replace(/[xy]/g, function (c) {
      const r = (Math.random() * 16) | 0,
        v = c == "x" ? r : (r & 0x3) | 0x8;
      return v.toString(16);
    })
    .toUpperCase();
};


const getMarkerLabel = (marker: Marker): string => {
  let label = markTypes.value.find((item: any) => item.value == marker.markType)?.label;
  return label!;
}



  // const getLabelByValue = (labelValue: string) => {
  //   console.log("labelValue:", labelValue);
  //   const label = labels.find((ele) => ele.value == labelValue);
  //   console.log("label:", label);
  //   return label;
  // };
</script>
<style scoped lang="scss">
.ai-label_drawer {
  width: 100%;
  height: 100%;
  background-color: #333;
  position: relative;
}

:deep(img, video) {
  max-width: none !important;
}

.tools {
  position: absolute;
  top: 5px;
  left: 5px;
  z-index: 1000;
  width: 50px;
  display: flex;
  flex-direction: column;
  background-color: #666;
  padding: 5px;
  border-radius: 5px;
}

.tools .el-button {
  width: 100%;
  margin: 5px 0 0 0;
}


#ai-map {
  background-color: #333;
}




:deep(.el-tabs--border-card) {
  background-color: transparent;
  border: none;
  color: #fff;
  height: 100%;

  .el-tabs__header {
    .el-tabs__item {
      height: 30px;
      line-height: 30px;
      background-color: #aaa;
      color: #fff;
    }

    .el-tabs__item.is-active {
      color: #fff;
      background-color: #666;
      border-left-color: #000;
      border-left-color: #000;
    }
  }

  .el-tabs__content {
    padding: 0px;
  }
}

.right-side {
  overflow-y: auto;
  background-color: #333;
  border-left: 1px solid #000;
}


.my-header {
  display: flex;
  flex-direction: row;
  justify-content: space-between;
  align-items: center;
}
</style>
  